﻿
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

namespace WSU.ChekaParallel.TestTask
{
    public static class TestBasic
    {
        public static void WaitAndPrintEnd(this Task atask)
        {
            atask.Wait();
            Console.WriteLine("task completed");
        }

        /// <summary>
        /// Action passed into task has no return value
        /// </summary>
        private static void TestTaskWithAction()
        {
            // ---------------------- take no argument
            Task atask = Task.Factory.StartNew(() => Console.WriteLine("action task with no argument."));
            atask.WaitAndPrintEnd();

            // ---------------------- task with argument
            atask = Task.Factory.StartNew((state) =>
                                              {
                                                  int totalNum = (int) state;
                                                  for (int index = 0; index < totalNum; ++index)
                                                      Console.WriteLine("hello {0}",index + 1);
                                              }, 5);
            atask.WaitAndPrintEnd();
        }

        /// <summary>
        /// Func passed into task will return a value
        /// </summary>
        private static void TestTaskWithFunc()
        {
            Task<string> atask = Task.Factory.StartNew(() =>
                {
                    Thread.Sleep(100);
                    return "cheka";
                });
            // -------- when invoking "Result" property and task hasn't completed, current thread will be blocked to wait for the result
            Console.WriteLine("task completed with result = {0}", atask.Result);
        }

        private static void TestExceptionInTask()
        {
            // throw null means throw a NullReferenceException
            Task<string> exceptionTask = Task.Factory.StartNew(() =>
            {
                throw null;
                return "NeverReturn";
            });

            try
            {
                string neverGotResult = exceptionTask.Result;
                Debug.Assert(false, "should never comes this line (an expected exception is missing)");
            }
            catch (AggregateException aggregatedExp)
            {
                Debug.Assert(aggregatedExp.InnerException is NullReferenceException,
                    "expected exception should be NullReferenceException");
                Console.WriteLine("expected exception with right type is caught");
            }
        }

        private static void TestReuseTask()
        {
            Task atask = new Task(Console.WriteLine, "Reusable or Not ?");
            atask.Start();
            atask.Wait();
            Console.WriteLine("First run completed.\n\nSecond run begins.");

            try
            {
                atask.Start();
                Debug.Fail("Impossible to run here, because above code should throw an exception.");
            }
            catch (InvalidOperationException ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("!!! Conclusion: Task cannot be reused.");
            }

        }

        #region [ entry ]

        public static void TestMain()
        {
            TestTaskWithAction();
            // TestTaskWithFunc();
            // TestExceptionInTask();
            TestReuseTask();
        }

        #endregion
    }
}